
import * as THREE from 'three';
import { GLTFLoader, OrbitControls } from 'three/examples/jsm/Addons.js';
import { Utils } from './Utils';
import { BarControls } from './BarControls';

const loader = new GLTFLoader();

interface IRow {
    url: string;
    title: string;
    tags?:string
}

export class ModelViewer {
    renderer: THREE.WebGLRenderer;
    camera: THREE.PerspectiveCamera;
    scene: THREE.Scene;
    controls: OrbitControls;

    barControls: BarControls;

    constructor(private canvas: HTMLCanvasElement) {
        const dpr = Math.min(2, window.devicePixelRatio);
        const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
        this.renderer = renderer;
        renderer.setClearColor(0xd3d3d3, 1);
        renderer.setPixelRatio(dpr);
        renderer.autoClear = false;

        const aspect = canvas.width / canvas.height;
        const camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 100);
        camera.position.z = 10;
        camera.position.y = 5;
        this.camera = camera;
        const scene = new THREE.Scene();
        this.scene = scene;
        camera.lookAt(scene.position);
        let controls = new OrbitControls(camera, renderer.domElement);
        this.controls = controls;

        this.barControls = new BarControls(renderer.domElement);

        this.resize();
        this.init();
    }

    init() {
        let scene = this.scene;
        scene.add(new THREE.HemisphereLight(0xaaaaaa, 0x444444, 1));
        const light = new THREE.DirectionalLight(0xffffff, 1.5);
        light.position.set(10, 10, 10);
        scene.add(light);
        this.scene.add(this.barControls.selected);

        this.randomObjects();
    }

    randomObjects() {
        let objects = this.barControls.objects;
        const geometries = [
            new THREE.BoxGeometry(1, 1, 1),
            new THREE.SphereGeometry(0.5, 12, 8),
            new THREE.DodecahedronGeometry(0.5),
            new THREE.CylinderGeometry(0.5, 0.5, 1, 12)
        ];
        for (let i = 0; i < 20; i++) {
            const geometry = geometries[geometries.length * Math.random() | 0];

            let color = Math.floor(Math.random() * 0x3f);
            color = (color & 0b110000) << 18 | (color & 0b1100) << 12 | (color & 0b11) << 6
            const material = new THREE.MeshStandardMaterial({ color });
            let mesh = new THREE.Mesh(geometry, material);
            mesh.position.x = i * 1.5;
            objects.add(mesh);
        }

    }

    resize() {
        let canvas = this.canvas;
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        this.camera.aspect = canvas.width / canvas.height;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(canvas.width, canvas.height);
    }

    async setRows(rows: Array<IRow>) {
        let objects = this.barControls.objects;
        objects.clear();
        objects.position.setX(0);
        let x = 0;
        for (let row of rows) {
            let gltf = await loader.loadAsync(row.url);
            let obj = gltf.scene;
            let box = Utils.computeBoundingBox(obj);
            let size = new THREE.Vector3();
            box.getSize(size);
            let r = Math.max(size.x, size.y, size.z);
            obj.scale.divideScalar(r);
            obj.position.setX(x);
            obj.userData.tags = row.tags;
            x += 1;
            obj.rotateY(Math.PI * 5 / 6);
            objects.add(obj);
        }

    }

    render(dt: number) {
        let angleY = 1 / 180;
        for (let obj of this.scene.children) {
            obj.rotateY(angleY);
        }
        this.renderer.clear();
        this.renderer.render(this.scene, this.camera);
        let bar = this.barControls;
        this.renderer.render(bar.sceneBar, bar._camera);
    }
}

